#include "cReceive.hpp"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

cReceive::cReceive(uint8_t* pDataBuffer,
                   uint16_t dataBufferSize,
                   uint16_t frameMaxSize,
                   uint16_t counterSize):
                   frameMaxSize(frameMaxSize)
{
    uint16_t cntUnitSize = frameMaxSize > 0xFF ? 2 : 1;
    uint8_t *pCntBuffer = pDataBuffer + (dataBufferSize - frameMaxSize * cntUnitSize);
    cQueue_Create_Static(&dataQueue, pDataBuffer, 1, dataBufferSize);
    cQueue_Create_Static(&cntQueue, pCntBuffer, cntUnitSize, counterSize);
    state = STATE_READY;
#if !!(CRECEIVE_TIMEOUT_ENABLE)
    get_time = 0;
    time_limit = 0;
    time_last = 0;
#endif
}
cReceive::~cReceive()
{
    
}

inline bool cReceive::isEmpty(void)
{
    return (cQueue_Empty(&cntQueue) || cQueue_Empty(&dataQueue));
}

inline bool cReceive::isFull(void)
{
    return (cQueue_Full(&cntQueue) == 0 || cQueue_Full(&dataQueue) == 0);
}

uint16_t cReceive::getMaxFrameSize(void)
{
    return this->frameMaxSize;
}

/**
 * @brief 写入数据到队列
 * @param pData 数据指针
 * @param dataSize 数据大小(Byte)
 * @retval true 写入成功
 * @retval false 写入失败
 * @note dataSize要小于等于frameMaxSize
 */
bool cReceive::push(uint8_t *&pData, uint16_t dataSize)
{
    if(state != STATE_READY || dataSize > frameMaxSize)
    {
        return false;
    }
    if (cQueue_Spare(&dataQueue) < dataSize || cQueue_Spare(&cntQueue) == 0)
    {
        return false;
    }
    cQueue_Pushs(&dataQueue, pData, dataSize);
    cQueue_Push(&cntQueue, &dataSize);
    return true;
}

/**
 * @brief 获取队列写入的指针
 * @param dataSize 要在外部写入的数据量
 * @retval uint8_t* 写指针/若没有足够空间则返回NULL
 * @note dataSize要小于等于frameMaxSize
 */
uint8_t *cReceive::push_start(uint16_t dataSize)
{
    uint8_t *pData;
    uint16_t edgeLen;
    if (state == STATE_BUSY || dataSize > frameMaxSize)
    {
        return NULL;
    }
    edgeLen = cQueue_GetWritePtrMargin(&dataQueue);
    if (edgeLen < dataSize)
    {
        if (cQueue_Spare(&dataQueue) < dataSize + edgeLen)
        {
            return NULL;
        }
        // 标记末端结束位置，从头开始，得到一段完整的空间
        endIndex = dataQueue.pWrite;
        cQueue_MoveWrite(&dataQueue, edgeLen);
    }
    state = STATE_BUSY;
    pData = (uint8_t*)cQueue_GetWriteAdr(&dataQueue);
    transferSize = dataSize;
    return pData;
}

/**
 * @brief 获取队列中的数据
 * @param pData 接收数据的缓存
 * @param bufSize 缓存大小
 * @retval int 写入缓存的数据量(Byte)
 */
int cReceive::pop(uint8_t *&pData, uint16_t bufSize)
{
    uint16_t dataSize;
    if (cQueue_Pop(&cntQueue, &dataSize) != CQUEUE_OK)
    {
        return 0;
    }
    if (dataSize == 0)
    {
        return 0;
    }
    if (endIndex != 0) //检测读指针是否在末端
    {
        if (dataQueue.pRead == endIndex)
        {
            // 跳过末端
            cQueue_Skip(&dataQueue, dataQueue.len - endIndex);
        }
    }
    dataSize = (dataSize > bufSize) ? bufSize : dataSize;
    if (cQueue_Pops(&dataQueue, pData, dataSize) != CQUEUE_OK)
    {
        state = STATE_ERROR;
        return 0;
    }
    return dataSize;
}

void cReceive::clear(void)
{
    cQueue_Clear(&dataQueue);
    cQueue_Clear(&cntQueue);
    state = STATE_READY;
    transferSize = 0;
}

#if !!(CRECEIVE_TIMEOUT_ENABLE)
void cReceive::pack_time_init(uint32_t (*get_time_callback)(void), uint32_t time_limit)
{
    this->get_time = get_time_callback;
    this->time_limit = time_limit;
}
#endif

int cReceive::receiveDone_callback(void)
{
    if (state == STATE_BUSY)
    {
        cQueue_Push(&cntQueue, &transferSize);
        transferSize = 0;
        state = STATE_IDLE;
    }
    return 0;
}
